1 /** 2 * Public imports free, malloc, realloc, memcpy, memcmp, memset. 3 * - toHeap!T executes malloc + memcpy 4 * - safeFree executes free and sets the reference to null 5 * - alloc!T is a malloc with the type size 6 * - allocSlice!T will return a heap allocated slice 7 * 8 */ 9 module hip.util.memory; 10 11 public import core.stdc.stdlib; 12 public import core.stdc.string:memcpy, memcmp, memset; 13 import hip.util.reflection; 14 15 version(WebAssembly) version = CustomRuntime; 16 version(PSVita) version = CustomRuntime; 17 version(CustomRuntimeTest) version = CustomRuntime; 18 19 version(CustomRuntime) 20 static import rt.hooks; 21 22 @nogc: 23 void setZeroMemory(T)(ref T variable) 24 { 25 memset(&variable, 0, T.sizeof); 26 } 27 28 29 T* alloc(T)(size_t count = 1){return cast(T*)core.stdc.stdlib.malloc(T.sizeof*count);} 30 T[] allocSlice(T)(size_t count){return alloc!T(count)[0..count];} 31 32 void* toHeap(T)(in T data) if(isReference!T) 33 { 34 version(CustomRuntime) 35 { 36 void* m = cast(void*)data; //WASM don't need to allocate as it is not ever deleted. 37 } 38 else 39 { 40 import core.memory; 41 void* m = cast(void*)data; 42 GC.addRoot(cast(void*)data); 43 } 44 return m; 45 } 46 47 void* toHeap(T)(T data) if(!isReference!T) 48 { 49 void* m = alloc!T; 50 memcpy(m, &data, T.sizeof); 51 return m; 52 } 53 54 void[] toHeapSlice(T)(T data) if(!is(T == void[])) 55 { 56 return toHeap(data)[0..T.sizeof]; 57 } 58 59 60 void freeGCMemory(void* data) 61 { 62 assert(data !is null, "Tried to free null data."); 63 version(CustomRuntime){rt.hooks.free(cast(ubyte*)data);} 64 else 65 { 66 import core.memory; 67 GC.removeRoot(data); 68 GC.free(data); 69 } 70 } 71 72 void freeGCMemory(ref void* data) //Remove ref. 73 { 74 assert(data !is null, "Tried to free null data."); 75 version(CustomRuntime){rt.hooks.free(cast(ubyte*)data);} 76 else 77 { 78 import core.memory; 79 GC.removeRoot(data); 80 GC.free(data); 81 } 82 data = null; 83 } 84 85 void freeGCMemory(ref void[] data) 86 { 87 assert(data.length, "Tried to free null data."); 88 freeGCMemory(data.ptr); 89 data = null; 90 } 91 92 void freeGCMemory(T)(ref T[] data) 93 { 94 freeGCMemory(cast(void*)data.ptr); 95 data = null; 96 } 97 98 void safeFree(T)(ref T data) if(isReference!T) 99 { 100 version(CustomRuntime) 101 { 102 free(cast(ubyte*)data); 103 } 104 else 105 { 106 import core.memory; 107 GC.removeRoot(cast(void*)data); 108 GC.free(cast(void*)data); 109 } 110 data = null; 111 } 112 113 void safeFree(ref void* data) 114 { 115 if(data != null) 116 free(data); 117 data = null; 118 } 119 void safeFree(ref void[] data) 120 { 121 if(data.ptr !is null) 122 free(data.ptr); 123 data = []; 124 } 125 126 class Pool(T) if(is(T == class) || is(T == interface)) 127 { 128 private 129 { 130 T[] objects; 131 int deadCount, maxPoolSize = -1; 132 pragma(inline, true) T getFirstDead(){return objects[getActiveCount];} 133 134 struct TInterface 135 { 136 pragma(inline, true) 137 { 138 static void deinitialize(T obj){obj.deinitialize();} 139 static void initialize(T obj){obj.initialize();} 140 } 141 } 142 } 143 144 /** 145 * 146 * Params: 147 * maxPoolSize = -1 means that Pool will never return null. It may still give array out of bounds if too many objects are created. 148 */ 149 this(int maxPoolSize = -1) 150 { 151 this.maxPoolSize = maxPoolSize; 152 } 153 int getActiveCount() => cast(int)objects.length - deadCount; 154 155 T get(Args...)(Args a) 156 { 157 T ret; 158 if(deadCount > 0) 159 { 160 ret = getFirstDead(); 161 deadCount--; 162 } 163 else 164 { 165 if(objects.length + 1 > maxPoolSize) return null; 166 int activeCount = getActiveCount(); 167 objects.length++; 168 if(deadCount) 169 objects[$-1] = objects[activeCount]; 170 objects[activeCount] = ret = new T(a); 171 } 172 TInterface.initialize(ret); 173 return ret; 174 } 175 176 int opApply(scope int delegate(ref T) dg) 177 { 178 int result = 0; 179 180 foreach (i; 0..getActiveCount) 181 { 182 result = dg(objects[i]); 183 if (result) 184 break; 185 } 186 return result; 187 } 188 189 void kill(T instance) 190 { 191 TInterface.deinitialize(instance); 192 deadCount++; 193 } 194 void clear() 195 { 196 foreach(obj; this) TInterface.deinitialize(obj); 197 deadCount = cast(int)objects.length; 198 } 199 }